package org.ceteca.explica.client.gui.common;

import java.math.BigDecimal;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;

import org.ceteca.explica.client.ClientContext;
import org.ceteca.explica.client.gui.ExplicaEditEntityView;
import org.ceteca.explica.client.gui.ExplicaGUIBuilder;
import org.ceteca.explica.core.ExplicaException;
import org.ceteca.explica.core.InterfaceErrors;
import org.ceteca.explica.core.InterfaceExplica;
import org.ceteca.explica.core.common.VatTypeOT;
import org.ceteca.explica.core.common.BaseVO;
import org.ceteca.explica.core.common.CommonManager;
import org.ceteca.explica.core.common.RegistryOT;
import org.ceteca.explica.core.installer.EntityLauncher;
import org.ceteca.explica.core.installer.EntityOT;
import org.ceteca.explica.core.installer.SubentityOT;
import org.ceteca.explica.core.util.OperationResult;
import org.ceteca.explica.core.util.ResultMessage;
import org.ceteca.explica.core.warehouse.InterfaceWarehouse;
import org.ceteca.javaglade.toolkit.swt.SwtDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;

public class VatTypeClient extends EntityLauncher {
	/** Instance of VO that holds the data of the selected product group */
	private VatTypeOT selVatType;
	
	/**
     * Message for logging the entity glade configuration file path.
     */
    public static final String EXPLICA_LOG_EDITVATTYPE_GLADEPATH = "The VAT type edition interface configuration file has been found at this path: %s";
    
    public VatTypeClient() {
    	super();
    	this.selVatType = null;
    }
	
    @Override
	public ArrayList getEntityFields() {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public ArrayList<ResultMessage> addEntity() {
		this.logger.info(String.format("Adding new entity..."));
		
		SwtDialog dialog = this.getEntityDialog();
		
		this.logger.info(String.format("Got entity dialog: %s", this.entityData.getName()));

		// Fill the form fields with the edited product data
		this.clearEntityData();
		this.logger.info(String.format("Entity selected registry data cleared: %s", this.entityData.getName()));
				
		this.selVatType = null;
		
		// Enable the entity edition widgets
		this.setEditionMode(true);
		
		this.logger.info(String.format("Opening entity dialog window: %s (%d, %d px)\n\tMINIMUM SIZE: (%d, %d px)", 
				this.entityData.getName(),
				dialog.getShell().getSize().x, dialog.getShell().getSize().y,
				dialog.getShell().getMinimumSize().x, dialog.getShell().getMinimumSize().y));
		
		// Show the edit product window
		dialog.open();

		return null;
	}

	@Override
	public OperationResult delEntity(ArrayList<Long> lSelRegistries) {
		OperationResult result = null;
		
		this.logger.info(String.format("Entity delete requested: (%s - %d) ...", this.entityData.getName(), this.getSelectedId()));
		
		this.logger.info(String.format("ENTITY_DATA=%s, ENTITY_VIEW=%s, ENTITY_PANEL=%s", this.entityData, this.entView, this.entityPanel));
		
		// Show the confirmation dialog and get the user response
		if (this.confirmEntityDelete()) {
			try {
				CommonManager manager = this.getRemoteCommonManager();
				System.out.println("Remote Manager located");
				
				result = manager.delVatTypes(lSelRegistries);
			}
			catch (AccessException aEx) {
				System.err.println("Se rechazó el acceso. Su sistema no tiene los permisos necesarios para realizar la operación remota!");
				aEx.printStackTrace();
			}
			catch (RemoteException rEx) {
				System.err.println("No se encontró el servicio o hubo errores al llamar a los métodos remotos!");
				rEx.printStackTrace();
			}
			catch (ExplicaException eEx) {
				System.err.println("Error accediendo a la BD para obtener el listado de productos!");
				eEx.printStackTrace();
			}
		}
		else {
			this.logger.info(String.format("Entity delete cancelled: (%s - %d)!", this.entityData.getName(), this.getSelectedId()));
			ArrayList lParams = new ArrayList();
			lParams.add(this.entityData.getName());
			lParams.add(this.getSelectedId());
			result = new OperationResult();
			result.addResultMessage(OperationResult.RESULT_WARNING, ClientContext.getInstance().getMsgCatalog().newResultMessage(InterfaceErrors.MSG_DELETE_ENTITY_CANCELLED, lParams));
		}
		
		return result;
	}
	
	public OperationResult delEntity() {
		OperationResult result = null;
		
		// Show the confirmation dialog and get the user response
		if (this.confirmEntityDelete()) {
			try {
				CommonManager manager = this.getRemoteCommonManager();
				System.out.println("Remote Manager located");
				
				result = manager.delVatType(this.getSelectedId());
			}
			catch (AccessException aEx) {
				System.err.println("Se rechazó el acceso. Su sistema no tiene los permisos necesarios para realizar la operación remota!");
				aEx.printStackTrace();
			}
			catch (RemoteException rEx) {
				System.err.println("No se encontró el servicio o hubo errores al llamar a los métodos remotos!");
				rEx.printStackTrace();
			}
			catch (ExplicaException eEx) {
				System.err.println("Error accediendo a la BD para obtener el listado de productos!");
				eEx.printStackTrace();
			}
		}
		else {
			this.logger.info(String.format("Entity delete cancelled: (%s - %d)!", this.entityData.getName(), this.getSelectedId()));
			ArrayList lParams = new ArrayList();
			lParams.add(this.entityData.getName());
			lParams.add(this.getSelectedId());
			result = new OperationResult();
			result.addResultMessage(OperationResult.RESULT_WARNING, ClientContext.getInstance().getMsgCatalog().newResultMessage(InterfaceErrors.MSG_DELETE_ENTITY_CANCELLED, lParams));
		}
		
		return result;
	}

	@Override
	public OperationResult editEntity() {
		this.logger.info(String.format("Editing entity: %s (%d)", this.entityData.getName(), this.selVatType.getIdVat()));
		
		SwtDialog dialog = this.getEntityDialog();
		
		this.logger.info(String.format("Got entity dialog: %s", this.entityData.getName()));

		// Fill the form fields with the edited product data
		this.fillEntityData();
		
		this.logger.info(String.format("Entity selected registry data filled: %s", this.entityData.getName()));
		
		// Connect the subentity selection (magnifying glass) buttons with their handlers
		this.connectSubentityButtons();
		
		// Enable the entity edition widgets
		this.setEditionMode(true);
		
		this.logger.info(String.format("Entity selected registry data filled: %s", this.entityData.getName()));
		
		this.logger.info(String.format("Opening entity dialog window: %s (%d, %d px)\n\tMINIMUM SIZE: (%d, %d px)", 
				this.entityData.getName(),
				dialog.getShell().getSize().x, dialog.getShell().getSize().y,
				dialog.getShell().getMinimumSize().x, dialog.getShell().getMinimumSize().y));
		
		// Show the edit product window
		dialog.open();

		return null;
	}
	
	@Override
	public OperationResult viewEntity() {
		this.logger.info(String.format("Editing entity: %s (%d)", this.entityData.getName(), this.selVatType.getIdVat()));
		
		SwtDialog dialog = this.getEntityDialog();
		
		this.logger.info(String.format("Got entity dialog: %s", this.entityData.getName()));

		// Fill the form fields with the edited product data
		this.fillEntityData();
		
		this.logger.info(String.format("Entity selected registry data filled: %s", this.entityData.getName()));
		
		// Connect the subentity selection (magnifying glass) buttons with their handlers
		this.connectSubentityButtons();
		
		// Enable the entity edition widgets
		this.setEditionMode(false);
		
		this.logger.info(String.format("Entity selected registry data filled: %s", this.entityData.getName()));
		
		this.logger.info(String.format("Opening entity dialog window: %s (%d, %d px)\n\tMINIMUM SIZE: (%d, %d px)", 
				this.entityData.getName(),
				dialog.getShell().getSize().x, dialog.getShell().getSize().y,
				dialog.getShell().getMinimumSize().x, dialog.getShell().getMinimumSize().y));
		
		// Show the edit product window
		dialog.open();

		return null;
	}

	@Override
	public OperationResult printEntity() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ArrayList queryEntity() {
		this.lRegistries = this.queryEntity(null, null); 
		return this.lRegistries;
	}

	@Override
	public ArrayList queryEntity(String fieldId, String value) {
		this.lRegistries = null;
		try {
			CommonManager manager = this.getRemoteCommonManager();
			System.out.println("WarehouseManager located");
			
			this.lRegistries = (ArrayList)manager.queryVatTypes(fieldId, value);
			StringBuffer logInfo = new StringBuffer();
			logInfo.append("Queried products: \n");
			for (int i=0; this.lRegistries != null && i<this.lRegistries.size(); i++) {
				System.out.println(this.lRegistries.get(i));
				logInfo.append(String.format("\n\t%d --> %s", i, this.lRegistries.get(i)));
			}
			this.logger.debug(logInfo.toString());
		}
		catch (AccessException aEx) {
			System.err.println("Se rechazó el acceso. Su sistema no tiene los permisos necesarios para realizar la operación remota!");
			aEx.printStackTrace();
		}
		catch (RemoteException rEx) {
			System.err.println("No se encontró el servicio o hubo errores al llamar a los métodos remotos!");
			rEx.printStackTrace();
		}
		catch (ExplicaException eEx) {
			System.err.println("Error accediendo a la BD para obtener el listado de productos!");
			eEx.printStackTrace();
		}
		return this.lRegistries;
	}

	@Override
	public ArrayList<RegistryOT> queryEntityWithFormat(String fieldId, String value) {
		ArrayList<RegistryOT> result = new ArrayList<RegistryOT>();
		
		// Get all the entity registries that fit the search criteria.
		this.lRegistries = this.queryEntity(fieldId, value);
		
		// For each registry format the data of the entity as String[] ready to be printed out in the tree.
		for (int i=0; this.lRegistries != null && i<this.lRegistries.size(); i++) {
			BaseVO group = (BaseVO)lRegistries.get(i);
			String[] lValues = group.format(this.entityData.getIdField(), this.entityData.getLFields());
			
			System.out.println("List of values for product: " + ((VatTypeOT)group).getIdVat() + ": " + lValues);
			
			RegistryOT reg = new RegistryOT(((VatTypeOT)group).getIdVat(), "id", lValues);
			
			result.add(reg);
		}
		
		return result;
	}

	@Override
	public void fillEntityData() {
		this.logger.info("Filling the entity with the selected registry data: " + this.entityEditGuiName);
		if (this.selVatType != null && this.entEditView != null) {
			// Set up the VAT type's id
			((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_ID_WIDGETNAME)).setText(String.format("%d", selVatType.getIdVat()));
			// Set up the VAT type's description
			((StyledText)this.getWidget(InterfaceExplica.EDIT_VATTYPE_DESCRIPTION_WIDGETNAME)).setText(selVatType.getDescription());
			// Set up the VAT type's tax percentage
//			((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_TAXPERCENTAGE_WIDGETNAME)).setText(String.format("%f", selVatType.getTaxPercentage()));
			((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_TAXPERCENTAGE_WIDGETNAME)).setText(selVatType.getTaxPercentage().toString());
			// Set up the VAT type's tax percentage
//			((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_RECEQUI_WIDGETNAME)).setText(String.format("%f", selVatType.getRecEquiPercentage()));
			((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_RECEQUI_WIDGETNAME)).setText(selVatType.getRecEquiPercentage().toString());
		}
	}

	@Override
	public void clearEntityData() {
		if (this.entEditView != null) {
			// Clear the VAT type's id
			((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_ID_WIDGETNAME)).setText("");
			// Clear the VAT type's description
			((StyledText)this.getWidget(InterfaceExplica.EDIT_VATTYPE_DESCRIPTION_WIDGETNAME)).setText("");
			// Clear the VAT type's tax percentage
			((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_TAXPERCENTAGE_WIDGETNAME)).setText("");
			// Clear the VAT type's tax percentage
			((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_RECEQUI_WIDGETNAME)).setText("");
		}
	}
	
	@Override
	public void selectEntity(Long idEntity) {
		System.out.println("------------- SELECT ENTITY -----------------");
		System.out.println("Num Entities: " + this.lRegistries.size());
		if (this.lRegistries != null && this.lRegistries.size() > 0) {
			int index = this.indexOf(idEntity);
			System.out.println("Selected index: " + index);
			if (index >= 0) {
				this.selVatType = (VatTypeOT)this.lRegistries.get(index);
				System.out.println("Selected product group: " + this.selVatType.getDescription());
			}
			else
				this.selVatType = null;
		}
		System.out.println("------------- SELECT ENTITY -----------------");
	}

	@Override
	public BaseVO getSelectedEntity() {
		return this.selVatType;
	}
	
	@Override
	public Long getSelectedId() {
		return (this.selVatType == null?null:this.selVatType.getIdVat());
	}

	@Override
	protected void buildEntityDialog() {
		this.logger.info(String.format("Building entity dialog: %s", this.entityData.getName()));
		
		this.entEditView = new ExplicaEditEntityView(this, this.logger, this.getEntityEditViewName(this.parentGui.getGuiName()), 
				this.parentGui, InterfaceExplica.EDIT_VATTYPE_DIALOG_NAME);
		this.entEditView.buildExplicaEditEntityView(InterfaceExplica.EXPLICA_EDIT_VATTYPE_GLADE_PATH);
	
		// Connect the edit entity buttons (Save, Cancel and Undo buttons)
		this.connectEditEntityButtons();
		
		// Save the entity dialog instance for latter use.
		SwtDialog d = this.entEditView.getDialog();
		d.getShell().setMinimumSize(800, 600);
		d.getShell().setSize(800, 600);
		d.getShell().setBackground(ExplicaGUIBuilder.getInstance().getColor(SWT.COLOR_BLUE));
		
		this.setEntityDialog(d);
	}

	@Override
	protected void connectSubentityButtons() {
		// No subentities defined for VAT type entity
	}

	@Override
	public void selectSubentity(String parentFieldId, BaseVO subentityOT) {
		// No subentities defined for VAT type entity
	}

	@Override
	public OperationResult saveEntity() {
		OperationResult result = new OperationResult();
		
		// Call the remote object to save the contents of the VAT type
		try {
			CommonManager manager = this.getRemoteCommonManager();
			
			VatTypeOT VATType= (VatTypeOT)this.getEntityData();
			result = manager.saveVatType(VATType);
			// Add the VAT type to the registries list if the VAT type is new and
			// has been succesfully saved
			if (result != null && OperationResult.RESULT_OK == result.getResult()) {
				if (this.selVatType == null) {
					this.lRegistries.add(VATType);
				} // if new VAT type has been successfully saved
				else {
					int index = this.indexOf(VATType.getInternalId());
					// Get the updated VAT type from the database
					VatTypeOT updVatType = this.getRemoteCommonManager().getVatType(VATType.getInternalId());
					this.lRegistries.set(index, updVatType);
				}
			} // if  the save operation was succesfully completed
			else {
				ExplicaGUIBuilder.getInstance().showConfirmationDialog(this.entEditView.getGui().getParentWindow().getShell(),
						result.getFormattedResult(), 
						String.format("Error saving entity (%s) registry ...", this.entityData.getName()),
						SWT.ICON_ERROR,
						SWT.OK
				);
			}
		}
		catch (ExplicaException ex) {
			System.err.println("Error guardando VAT type!");
			ex.printStackTrace();
			result.addResultMessage(OperationResult.RESULT_ERROR, ex.getResMsg());
		}
		catch (RemoteException rEx) {
			System.err.println("No se encontró el servicio o hubo errores al llamar a los métodos remotos!");
			rEx.printStackTrace();
			
			result.addResultMessage(OperationResult.RESULT_ERROR, 
					ClientContext.getInstance().getMsgCatalog().newResultMessage(InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND, rEx));
		}
		
		return result;
		
	}

	@Override
	public BaseVO getEntityData() {
		VatTypeOT VATType = new VatTypeOT();
		
		if (this.entEditView != null) {
			// Set up the vat type's description
			VATType.setDescription(((StyledText)this.getWidget(InterfaceExplica.EDIT_VATTYPE_DESCRIPTION_WIDGETNAME)).getText());
			// Set up the vat type's tax percentage
			BigDecimal tax = new BigDecimal(((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_TAXPERCENTAGE_WIDGETNAME)).getText());
			VATType.setTaxPercentage(tax);
			// Set up the vat type's rec equi
			BigDecimal recEqui = new BigDecimal(((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_RECEQUI_WIDGETNAME)).getText());
			VATType.setRecEquiPercentage(recEqui);
		}
		
		if (this.selVatType != null) {
			VATType.setVersion(this.selVatType.getVersion());
			VATType.setIdVat(this.selVatType.getIdVat());
		}
		
		return VATType;
	}

	@Override
	public void updateEntityData() {
		if (this.selVatType != null && this.entEditView != null) {
			// Set up the product's description
			this.selVatType.setDescription(((StyledText)this.getWidget(InterfaceExplica.EDIT_VATTYPE_DESCRIPTION_WIDGETNAME)).getText());
//			 Set up the vat type's tax percentage
			BigDecimal tax = new BigDecimal(((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_TAXPERCENTAGE_WIDGETNAME)).getText());
			this.selVatType.setTaxPercentage(tax);
			// Set up the vat type's rec equi
			BigDecimal recEqui = new BigDecimal(((Text)this.getWidget(InterfaceExplica.EDIT_VATTYPE_RECEQUI_WIDGETNAME)).getText());
			this.selVatType.setRecEquiPercentage(recEqui);
		}
		
	}
	
	private CommonManager getRemoteCommonManager() throws ExplicaException {
		try {
			// El servidor de registro de RMI devuelve un objeto remoto genérico
			// que debe ser convertido al tipo correspondiente. Ojo: El nombre por el
			// que buscamos debe coincidir con el que se le dio al servicio en el
			// momento en que se registró (WarehouseManagerImpl.java)
			Registry registry = LocateRegistry.getRegistry(InterfaceExplica.RMI_REGISTRY_PORT);
            System.out.println("Registry located");
			CommonManager manager = (CommonManager)registry.lookup(InterfaceExplica.JNDI_COMMON_MANAGER_EXPORT_NAME);
			System.out.println("CommonManager located");
			
			return manager;
		}
		catch (AccessException aEx) {
			System.err.println("Se rechazó el acceso. Su sistema no tiene los permisos necesarios para realizar la operación remota!");
			aEx.printStackTrace();
			
			throw new ExplicaException(ClientContext.getInstance().getMsgCatalog().newResultMessage(
					InterfaceErrors.ERR_RMI_NO_ACCESS, aEx, (Object)InterfaceExplica.JNDI_WAREHOUSE_MANAGER_EXPORT_NAME, (Object)null));
		}
		catch (NotBoundException nEx) {
			System.err.println("El nombre del objeto no está asociado a un objeto remoto registrado!");
			nEx.printStackTrace();
			
			throw new ExplicaException(ClientContext.getInstance().getMsgCatalog().newResultMessage(
					InterfaceErrors.ERR_RMI_NOT_BOUND, nEx, (Object)InterfaceExplica.JNDI_WAREHOUSE_MANAGER_EXPORT_NAME, (Object)null));
		}
		catch (RemoteException rEx) {
			System.err.println("No se encontró el servicio o hubo errores al llamar a los métodos remotos!");
			rEx.printStackTrace();
			
			throw new ExplicaException(ClientContext.getInstance().getMsgCatalog().newResultMessage(
					InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND, rEx, (Object)InterfaceExplica.JNDI_WAREHOUSE_MANAGER_EXPORT_NAME, (Object)null));
		}
	}
	
	/**
	 * Queries the selected entity for all the detail subentities
	 * associated with it.
	 * @param entData SubentityOT, data of the detail subentity to query for.
	 * @return ArrayList, list of detail subentity registries assigned
	 * to the master detail registry.
	 */
	public ArrayList querySubentities(SubentityOT entData) {
		return null;
	}

	@Override
	protected void setEditionMode(boolean enabled) {
		// Get the Vat Type's code widget
		Control c = (Control)this.getWidget(InterfaceExplica.EDIT_VATTYPE_ID_WIDGETNAME);
		c.setEnabled(enabled);
		
		// Get the Vat Type's description widget
		c = (Control)this.getWidget(InterfaceExplica.EDIT_VATTYPE_DESCRIPTION_WIDGETNAME);
		c.setEnabled(enabled);
	}
}
